#include "register.h"
#include "libc/stdint.h"
#include "driver/interrupt_id.h"

struct pl011{
    uint32_t UARTDR;
    uint32_t UARTRSR;
    uint32_t Reserved1[4];
    uint32_t UARTFR;
    uint32_t Reserved2;
    uint32_t UARTILPR;
    uint32_t UARTIBRD;
    uint32_t UARTFBRD;
    uint32_t UARTLCR_H;
    uint32_t UARTCR;
    uint32_t UARTIFLS;
    uint32_t UARTIMSC;
    uint32_t UARTRIS;
    uint32_t UARTMIS;
    uint32_t UARTICR;
    uint32_t UARTDMACR;
    uint32_t Reserved3[13];
    uint32_t Reserved4[4];
    uint32_t Reserved5[976];
    uint32_t Reserved6[4];
    uint32_t UARTPeriphID0;
    uint32_t UARTPeriphID1;
    uint32_t UARTPeriphID2;
    uint32_t UARTPeriphID3;
    uint32_t UARTPCellID0;
    uint32_t UARTPCellID1;
    uint32_t UARTPCellID2;
    uint32_t UARTPCellID3;
}pl011;

struct pl011* pl011_reg_map = (struct pl011*)0x09000000;

uint32_t baudrate = 115200;
uint32_t data_bits = 8;
uint32_t stop_bits = 1;

char BUFFER[256];
uint32_t pointer = 0;

void put_pl011(const char* str){
    while(*str != '\0'){
        pl011_reg_map->UARTDR = *str;
        str++;
    }
}

void calculate_divisiors(uint32_t *integer, uint32_t *fractional)
{
    // 64 * F_UARTCLK / (16 * B) = 4 * F_UARTCLK / B
    const uint32_t div = 4 * get_frq() / baudrate;

    *fractional = div & 0x3f;
    *integer = (div >> 6) & 0xffff;
}

void pl011_init(){
    BUFFER[pointer] = '\0';

    on_receive(BUFFER);

    interrupt_init(EL1_SERIEL_CLICK, LEVEL_MODE);

    // pl011_reg_map->UARTIMSC |= (0x1 << 5);
    
    // Disable UART before anything else
    pl011_reg_map->UARTCR = (0x0);

    // Wait for any ongoing transmissions to complete
    while((pl011_reg_map->UARTFR & (0x1 << 3))){}

    // Flush FIFOs
    pl011_reg_map->UARTLCR_H &= ~(0x1 << 4);

    // Set frequency divisors (UARTIBRD and UARTFBRD) to configure the speed
    uint32_t ibrd, fbrd;
    calculate_divisiors(&ibrd, &fbrd);
    pl011_reg_map->UARTIBRD = ibrd;
    pl011_reg_map->UARTFBRD = fbrd;

    // Configure data frame format according to the parameters (UARTLCR_H).
    // We don't actually use all the possibilities, so this part of the code
    // can be simplified.
    pl011_reg_map->UARTLCR_H = 0x0;
    // WLEN part of UARTLCR_H, you can check that this calculation does the
    // right thing for yourself
    pl011_reg_map->UARTLCR_H |= ((data_bits - 1) & 0x3) << 5;
    // Configure the number of stop bits
    if (stop_bits == 2)
        pl011_reg_map->UARTLCR_H |= (1 << 3);

    // Mask all interrupts by setting corresponding bits to 1
    pl011_reg_map->UARTIMSC = 0x7ff;

    // Disable DMA by setting all bits to 0
    pl011_reg_map->UARTDMACR = 0x0;

    // I only need transmission, so that's the only thing I enabled.
    pl011_reg_map->UARTCR = 0x1;
    // Finally enable UART
    pl011_reg_map->UARTCR = (0x1) | (0x1 << 8);


    pl011_reg_map->UARTIMSC &= ~(0x1 << 5);

   

    // pl001_print_map();
}


void pl011_handler(){
    // printk("pl011_handler\n");

    if((pl011_reg_map->UARTRIS & (0x1 << 4)) != 0){
        char str = (char)(pl011_reg_map->UARTDR & 0xFF);
        switch (str){
            case 13:
                on_receive(BUFFER);
                pointer = 0;
                BUFFER[pointer] = '\0';
                break;

            case 65: // 上
            case 66: // 下
            case 67: // 右
            case 68: // 左
                if(pointer>1){
                    if(BUFFER[pointer-1] == 91 && BUFFER[pointer-2] == 27){
                        pointer -=2;
                        BUFFER[pointer] = '\0';
                        break;
                    }
                }

                
            case 27:
            case 91:

            
            default:
                printk("%c", str);
                BUFFER[pointer++] = str;
                BUFFER[pointer] = '\0';
                break;
        }
    }

    // pl011_reg_map->UARTICR |= (0x1 << 5);
    // pl011_reg_map->UARTICR |= (0x1 << 4);

    // printk("UARTICR: %x(%b)\n", &pl011_reg_map->UARTICR, pl011_reg_map->UARTICR);
    // printk("UARTIMSC: %x(%b)\n", &pl011_reg_map->UARTIMSC, pl011_reg_map->UARTIMSC);
    // printk("UARTRIS: %x(%b)\n", &pl011_reg_map->UARTRIS, pl011_reg_map->UARTRIS);
}


void pl011_print_map(){
    printk("------ print pl011 -----\n");
    printk("UARTDR: %x(%b)\n", &pl011_reg_map->UARTDR, pl011_reg_map->UARTDR);
    printk("UARTDR: %x(%b)\n", &pl011_reg_map->UARTRSR, pl011_reg_map->UARTRSR);
    printk("Reserved1: %x(%b)\n", &pl011_reg_map->Reserved1, pl011_reg_map->Reserved1);
    printk("UARTFR: %x(%b)\n", &pl011_reg_map->UARTFR, pl011_reg_map->UARTFR);
    printk("Reserved2: %x(%b)\n", &pl011_reg_map->Reserved2, pl011_reg_map->Reserved2);
    printk("UARTILPR: %x(%b)\n", &pl011_reg_map->UARTILPR, pl011_reg_map->UARTILPR);
    printk("UARTIBRD: %x(%b)\n", &pl011_reg_map->UARTIBRD, pl011_reg_map->UARTIBRD);
    printk("UARTFBRD: %x(%b)\n", &pl011_reg_map->UARTFBRD, pl011_reg_map->UARTFBRD);
    printk("UARTLCR_H: %x(%b)\n", &pl011_reg_map->UARTLCR_H, pl011_reg_map->UARTLCR_H);
    printk("UARTCR: %x(%b)\n", &pl011_reg_map->UARTCR, pl011_reg_map->UARTCR);
    printk("UARTIFLS: %x(%b)\n", &pl011_reg_map->UARTIFLS, pl011_reg_map->UARTIFLS);
    printk("UARTIMSC: %x(%b)\n", &pl011_reg_map->UARTIMSC, pl011_reg_map->UARTIMSC);
    printk("UARTRIS: %x(%b)\n", &pl011_reg_map->UARTRIS, pl011_reg_map->UARTRIS);
    printk("UARTMIS: %x(%b)\n", &pl011_reg_map->UARTMIS, pl011_reg_map->UARTMIS);
    printk("UARTICR: %x(%b)\n", &pl011_reg_map->UARTICR, pl011_reg_map->UARTICR);
    printk("UARTDMACR: %x(%b)\n", &pl011_reg_map->UARTDMACR, pl011_reg_map->UARTDMACR);
    printk("Reserved3: %x(%b)\n", &pl011_reg_map->Reserved3, pl011_reg_map->Reserved3);
    printk("Reserved4: %x(%b)\n", &pl011_reg_map->Reserved4, pl011_reg_map->Reserved4);
    printk("Reserved5: %x(%b)\n", &pl011_reg_map->Reserved5, pl011_reg_map->Reserved5);
    printk("Reserved6: %x(%b)\n", &pl011_reg_map->Reserved6, pl011_reg_map->Reserved6);
    printk("UARTPeriphID0: %x(%b)\n", &pl011_reg_map->UARTPeriphID0, pl011_reg_map->UARTPeriphID0);
    printk("UARTPeriphID1: %x(%b)\n", &pl011_reg_map->UARTPeriphID1, pl011_reg_map->UARTPeriphID1);
    printk("UARTPeriphID2: %x(%b)\n", &pl011_reg_map->UARTPeriphID2, pl011_reg_map->UARTPeriphID2);
    printk("UARTPeriphID3: %x(%b)\n", &pl011_reg_map->UARTPeriphID3, pl011_reg_map->UARTPeriphID3);
    printk("UARTPCellID0: %x(%b)\n", &pl011_reg_map->UARTPCellID0, pl011_reg_map->UARTPCellID0);
    printk("UARTPCellID1: %x(%b)\n", &pl011_reg_map->UARTPCellID1, pl011_reg_map->UARTPCellID1);
    printk("UARTPCellID2: %x(%b)\n", &pl011_reg_map->UARTPCellID2, pl011_reg_map->UARTPCellID2);
    printk("UARTPCellID3: %x(%b)\n", &pl011_reg_map->UARTPCellID3, pl011_reg_map->UARTPCellID3);
    printk("------ end pl011 -----\n");
}





